package httpclient;

import com.fasterxml.jackson.core.type.TypeReference;
import common.utils.JsonUtils;
import httpclient.bean.HttpResult;
import httpclient.encrypt.BodyEncrypt;
import httpclient.listener.IHttpClientHandler;
import httpclient.signature.IUrlSignature;
import okhttp3.*;
import okhttp3.internal.tls.OkHostnameVerifier;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.SocketTimeoutException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

public class HttpClient {

    private final static MediaType CONTEXT_TYPE_STREAM = MediaType.parse("application/octet-stream");
    private final static MediaType CONTEXT_TYPE_JSON = MediaType.parse("application/json;charset=utf-8");
    private final static MediaType CONTEXT_TYPE_TEXT = MediaType.parse("text/plain;charset=utf-8");

    private static HttpClient mHttpClient;

    private OkHttpClient mOkHttpClient;
    static Logger logger = LoggerFactory.getLogger(HttpClient.class);

    private IUrlSignature mUrlSignature;
    private BodyEncrypt mBodyEncrypt;
    private Class<?> mReturnType;
    private ContextType mContextType;

    public enum ContextType {

        STREAM("application/octet-stream"),
        JSON("application/json;charset=utf-8"),
        TEXT("text/plain;charset=utf-8"),
        FORM("application/x-www-pojo-urlencoded;charset=utf-8"),
        MULTIPART_FORM_DATA("multipart/pojo-data");

        private String contextType;

        ContextType(String contextType) {
            this.contextType = contextType;
        }

        public String getContextType() {
            return contextType;
        }
    }


    /**
     * http方法
     */
    public enum Method {

        POST("POST"),
        PUT("PUT"),
        GET("GET"),
        DELETE("DELETE");

        private String method;

        Method(String method) {
            this.method = method;
        }

        public String getString() {
            return method;
        }
    }


    public static HttpClient getInstance() {
        if (mHttpClient == null) {
            synchronized (HttpClient.class) {
                if (mHttpClient == null) {
                    mHttpClient = new HttpClient();
                }
            }
        }
        return mHttpClient;
    }

    private HttpClient() {
        mReturnType = String.class;
        mContextType = ContextType.FORM;
        mOkHttpClient = new OkHttpClient.Builder()
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .build();
    }



    /**
     * 初始化一个httpclient的配置builder
     *
     * @return
     */
    public Builder newBuilder() {
        return new Builder();
    }


    /**
     * 获取读超时时间
     *
     * @return 毫秒
     */
    public int getReadTimeout() {
        return mOkHttpClient.readTimeoutMillis();
    }

    /**
     * 获取写超时时间
     *
     * @return 毫秒
     */
    public int getWriteTimeout() {
        return mOkHttpClient.writeTimeoutMillis();
    }

    /**
     * 获取连接超时时间
     *
     * @return 毫秒
     */
    public int getConnectionTimeout() {
        return mOkHttpClient.connectTimeoutMillis();
    }

    public HttpClient setUrlSignature(IUrlSignature urlSignature) {
        this.mUrlSignature = urlSignature;
        return this;
    }

    public HttpClient setBodyEncrypt(BodyEncrypt bodyEncrypt) {
        this.mBodyEncrypt = bodyEncrypt;
        return this;
    }

    /**
     * 设置返回结果类型
     *
     * @param returnType 返回结果类型
     * @return httpclient
     */
    public HttpClient setReturnType(Class<?> returnType) {
        if (returnType == null) {
            returnType = String.class;
        }
        this.mReturnType = returnType;
        return this;
    }



    public final class Builder {
        private OkHttpClient.Builder gOkHttpBuilder;
        private Request request;

        private Builder() {
            gOkHttpBuilder = mOkHttpClient.newBuilder();
        }

        public Builder(Request request) {
            this();
            this.request = request;
        }

        /**
         * 设置读超时时间
         *
         * @param milliSeconds 超时时间毫秒
         * @return Builder
         */
        public Builder setReadTimeout(long milliSeconds) {
            gOkHttpBuilder.readTimeout(milliSeconds, TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置写超时时间
         *
         * @param milliSeconds 超时时间毫秒
         * @return Builder
         */
        public Builder setWriteTimeout(int milliSeconds) {
            gOkHttpBuilder.writeTimeout(milliSeconds, TimeUnit.MILLISECONDS);
            return this;
        }

        /**
         * 设置连接超时时间
         *
         * @param milliSeconds 超时时间毫秒
         * @return Builder
         */
        public Builder setConnectionTimeout(int milliSeconds) {
            gOkHttpBuilder.connectTimeout(milliSeconds, TimeUnit.MILLISECONDS);
            return this;
        }


        /**
         * 信任所有https的服务器
         *
         * @return Builder
         */
        public Builder trustAllHosts() {
            SSLContext context = null;
            try {
                context = SSLContext.getInstance("TLS");
                context.init(null, new X509TrustManager[]{new X509TrustManager() {

                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                    }

                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                    }

                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }}, new SecureRandom());
                gOkHttpBuilder.sslSocketFactory(context.getSocketFactory());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            return this;
        }


        /**
         * 从流中加载证书
         *
         * @param certificates 证书流
         * @return Builder
         */
        public Builder setCertificatesFromInputStream(InputStream... certificates) {
            if (certificates == null || certificates.length == 0) {
                return this;
            }
            try {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(null);
                int index = 0;
                for (InputStream certificate : certificates) {
                    String certificateAlias = Integer.toString(index++);
                    keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
                    if (certificate != null) {
                        try {
                            certificate.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                SSLContext sslContext = SSLContext.getInstance("TLS");
                TrustManagerFactory trustManagerFactory =
                        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
                sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
                gOkHttpBuilder.sslSocketFactory(sslContext.getSocketFactory());
            } catch (CertificateException e) {
                e.printStackTrace();
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
            return this;
        }

        /**
         * 设置是否验证主机
         *
         * @param enable 验证开关
         * @return Builder
         */
        public Builder enableHostnameVerifier(boolean enable) {
            if (enable) {
                gOkHttpBuilder.hostnameVerifier(OkHostnameVerifier.INSTANCE);
            } else {
                gOkHttpBuilder.hostnameVerifier(new HostnameVerifier() {

                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
            }
            return this;
        }


        /**
         * 重新生成全局httpclient配置
         *
         * @return HttpClient
         */
        public HttpClient build(){
            if (request != null) {
                return mHttpClient;
            }
            synchronized (HttpClient.class) {
                mOkHttpClient = gOkHttpBuilder.build();
            }
            return mHttpClient;
        }

        /**
         * 重新生成单次HttpClient.Request的配置
         *
         * @return HttpClient.Request
         */
        public Request buildRequest() {
            if (request == null) {
                return null;
            }
            return new Request(gOkHttpBuilder.build(), request);
        }

    }

    public class Request<R> {

        private Object target;
        private Object body;
        private Type returnType;
        private boolean returnResponse;
        private boolean downLoad;
        private String rawUrl;
        private String url;
        private Method method;
        private Map<String, String> headers;
        private Map<String, Object> urlArgs;
        private ContextType contextType;

        private OkHttpClient okHttpClient;

        private IUrlSignature urlSignature;
        private boolean enableUrlSignature;
        private BodyEncrypt bodyEncrypt;
        private boolean enableBodyEncrypt;

        private IHttpClientHandler handler;
        private boolean serial;


        public Request() {
            this.okHttpClient = mOkHttpClient;
            this.enableUrlSignature = true;
            this.enableBodyEncrypt = true;
            this.method = Method.GET;
            this.headers = new HashMap<String, String>();
            this.urlArgs = new HashMap<String, Object>();
            Type superclass = this.getClass().getGenericSuperclass();
            if (superclass instanceof Class) {
                return;
            }
            ParameterizedType pType = (ParameterizedType) superclass;
            this.returnType = pType.getActualTypeArguments()[0];
        }

        private Request(OkHttpClient okHttpClient, Request<R> request) {
            this.okHttpClient = okHttpClient;
            this.target = request.target;
            this.body = request.body;
            this.returnType = request.returnType;
            this.returnResponse = request.returnResponse;
            this.downLoad = request.downLoad;
            this.rawUrl = request.rawUrl;
            this.url = request.url;
            this.method = request.method;
            this.headers = request.headers;
            this.urlArgs = request.urlArgs;
            this.contextType = request.contextType;
            this.okHttpClient = request.okHttpClient;
            this.urlSignature = request.urlSignature;
            this.enableUrlSignature = request.enableUrlSignature;
            this.bodyEncrypt = request.bodyEncrypt;
            this.enableBodyEncrypt = request.enableBodyEncrypt;
            this.handler = request.handler;
            this.serial = request.serial;
        }

        /**
         * 生成request的配置Builder
         *
         * @return
         */
        public final Builder newBuilder() {
            return new Builder(this);
        }

        public final Request<R> setUrlSignature(IUrlSignature urlSignature) {
            this.urlSignature = urlSignature;
            return this;
        }

        public final Request<R> setBodyEncrypt(BodyEncrypt bodyEncrypt) {
            mBodyEncrypt = bodyEncrypt;
            return this;
        }

        public final Request<R> post() {
            this.method = Method.POST;
            return this;
        }

        public final Request<R> get() {
            this.method = Method.GET;
            return this;
        }

        /**
         * 设置request为put请求
         *
         * @return
         */
        public final Request<R> put() {
            this.method = Method.PUT;
            return this;
        }

        /**
         * 设置request为delete请求
         *
         * @return
         */
        public final Request<R> delete() {
            this.method = Method.DELETE;
            return this;
        }


        public final Request<R> setBody(Object body) {
            this.body = body;
            return this;
        }

        public final Request<R> setUrl(String url) {
            this.url = url;
            this.rawUrl = url;
            return this;
        }

        /**
         * 设置异步请求是否串行
         *
         * @param serial 是否串行
         * @return Request
         */
        public final Request<R> setSerial(boolean serial) {
            this.serial = serial;
            return this;
        }

        /**
         * 设置头信息
         *
         * @param headers 头信息
         * @return Request
         */
        public final Request<R> setHeaders(Map<String, String> headers) {
            this.headers.putAll(headers);
            return this;
        }

        /**
         * 设置头信息
         *
         * @param name  头名称
         * @param value 值
         * @return Request
         */
        public final Request<R> setHeader(String name, String value) {
            this.headers.put(name, value);
            return this;
        }

        /**
         * 设置url参数
         *
         * @param urlArgs url参数
         * @return Request
         */
        public final Request<R> setUrlArgs(Map<String, Object> urlArgs) {
            this.urlArgs.putAll(urlArgs);
            return this;
        }

        /**
         * 设置Url参数
         *
         * @param name  参数名
         * @param value 参数值
         * @return Request
         */
        public final Request<R> setUrlArg(String name, String value) {
            this.urlArgs.put(name, value);
            return this;
        }

        /**
         * 设置http返回类型
         *
         * @param returnType 返回类型
         * @return Request
         */
        public final Request<R> setReturnType(Class<R> returnType) {
            this.returnType = returnType;
            if (returnType == Response.class) {
                this.returnResponse = true;
            }
            return this;
        }

        /**
         * 设置是否返回Response
         *
         * @param returnResponse 是否返回Response
         * @return Request
         */
        public final Request<R> setReturnResponse(boolean returnResponse) {
            this.returnResponse = returnResponse;
            return this;
        }

        /**
         * 设置Context-type
         *
         * @param contextType context-type
         * @return Request
         */
        public final Request<R> setContextType(ContextType contextType) {
            this.contextType = contextType;
            return this;
        }

        /**
         * 设置是否启用url签名
         *
         * @param enableUrlSignature 是否启用url签名
         * @return Request
         */
        public final Request<R> setEnableUrlSignature(boolean enableUrlSignature) {
            this.enableUrlSignature = enableUrlSignature;
            return this;
        }

        /**
         * 设置是否启用body加解密
         *
         * @param enableBodyEncrypt body加解密
         * @return Request
         */
        public final Request<R> setEnableBodyEncrypt(boolean enableBodyEncrypt) {
            this.enableBodyEncrypt = enableBodyEncrypt;
            return this;
        }


        /**
         * 是否返回Response
         *
         * @return boolean
         */
        public final boolean isReturnResponse() {
            return this.returnResponse;
        }

        /**
         * 是否是下载请求
         *
         * @return boolean
         */
        public final boolean isDownLoad() {
            return this.downLoad;
        }

        /**
         * 获取Url签名
         *
         * @return IUrlSignature
         */
        public final IUrlSignature getUrlSignature() {
            if (!enableUrlSignature) {
                return null;
            }
            return this.urlSignature == null ? mUrlSignature : urlSignature;
        }

        /**
         * 获取body加解密接口
         *
         * @return IBodyEncrypt
         */
        public final BodyEncrypt getBodyEncrypt() {
            if (!enableBodyEncrypt) {
                return null;
            }
            return bodyEncrypt == null ? mBodyEncrypt : bodyEncrypt;
        }

        /**
         * 获取context-type
         *
         * @return ContextType
         */
        public final ContextType getContextType() {
            if (this.contextType == null) {
                return mContextType;
            }
            return contextType;
        }

        /**
         * 获取请求方法
         *
         * @return Method
         */
        public final Method getMethod() {
            return this.method;
        }

        /**
         * 获取头信息
         *
         * @return Map<String,String>
         */
        public final Map<String, String> getHeaders() {
            return this.headers;
        }

        /**
         * 获取头信息
         *
         * @param name key
         * @return String
         */
        public final String getHeader(String name) {
            return this.headers.get(name);
        }

        /**
         * 获取url参数
         *
         * @return Map<String,String>
         */
        public final Map<String, Object> getUrlArgs() {
            return this.urlArgs;
        }

        /**
         * 获取url参数
         *
         * @param name 参数名
         * @return Object
         */
        public final Object getUrlArg(String name) {
            return this.urlArgs.get(name);
        }

        /**
         * 获取body
         *
         * @return B
         */
        public final Object getBody() {
            return this.body;
        }


        /**
         * 获取返回类型
         *
         * @return Class<?>
         */
        public final Type getReturnType() {
            if (downLoad || returnResponse) {
                return Response.class;
            }
            if (this.returnType == null) {
                return mReturnType;
            }
            return this.returnType;
        }

        /**
         * 获取原始Url路径
         *
         * @return String
         */
        public final String getRawUrl() {
            return this.rawUrl;
        }

        /**
         * 获取最终url路径
         *
         * @return String
         */
        public final String getUrl() {
            return this.url;
        }

        /**
         * 获取请求标识
         *
         * @return T
         */
        public final Object getTarget() {
            return this.target;
        }

        /**
         * 获取异步处理的handler
         *
         * @return IIHttpClientHandler
         */
        public final IHttpClientHandler getHandler() {
            return this.handler;
        }

        /**
         * 发起同步http请求
         *
         * @param url url地址
         * @return HttpResult<R>
         */
        public final HttpResult<R> request(String url) {
            setUrl(url);
            return request();
        }

        public final HttpResult<R> request() {
            if (StringUtils.isEmpty(this.rawUrl)) {
                return new HttpResult.Builder<R>().setError("url地址错误").build();
            }
            String temUrl = this.rawUrl.toLowerCase();
            if (!temUrl.startsWith("http://") && !temUrl.startsWith("https://")) {
                return new HttpResult.Builder<R>().setError("url地址错误").build();
            }
            switch (this.method) {
                case GET:
                case DELETE:
                    return requestNoBody();
                case POST:
                case PUT:
                default:
                    if (body == null) {
                        return requestNoBody();
                    }
                    return requestWithBody();
            }
        }

        public final void request(String url,Object target,IHttpClientHandler handler){
            setUrl(url);
            request(target,handler);
            return;
        }

        public final void request(final Object target, final IHttpClientHandler handler){
            final FutureTask futureTask = new FutureTask(new Callable() {
                public HttpResult<R> call() throws Exception {
                    return Request.this.request();
                }
            });
            Observable.create(new Observable.OnSubscribe<HttpResult<R>>() {

                public void call(Subscriber<? super HttpResult<R>> subscriber) {
                    futureTask.run();
                    HttpResult<R> httpResult;
                    try {
                        httpResult = (HttpResult) futureTask.get();
                    }catch (Exception e) {
                        HttpClient.logger.error("error", e);
                        httpResult = new HttpResult.Builder().setError("Future处理异常").build();
                    }
                    subscriber.onNext(httpResult);
                }
            }).subscribeOn(Schedulers.io()).subscribe(new Action1<HttpResult<R>>() {
                public void call(HttpResult<R> rHttpResult) {
                    if (handler!=null){
                        if(rHttpResult.isSuccessful()) {
                            handler.httpClientSuccess(target, rHttpResult);
                        } else {
                            handler.httpClientError(target, rHttpResult);
                        }
                    }
                }
            });
        }


        private final HttpResult<R> requestNoBody() {
            url = wrapperUrl(url);
            okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
            addHeader(builder, headers);
            builder.url(url);

            RequestBody requestBody = null;
            switch (method) {
                case POST:
                case PUT:
                    requestBody = RequestBody.create(null, new byte[0]);

            }
            builder.method(method.getString(), requestBody);
            return requestHttp(builder.build());
        }

        private final HttpResult<R> requestWithBody() {
            url = wrapperUrl(url);
            okhttp3.Request.Builder builder = new okhttp3.Request.Builder();
            addHeader(builder, headers);
            builder.url(url);
            RequestBody requestBody = null;
            String content = null;
            MediaType mediaType = null;
            if (this.body instanceof String) {
                content = (String) this.body;
                mediaType = CONTEXT_TYPE_TEXT;
            } else if (this.body instanceof File) {
                requestBody = RequestBody.create(CONTEXT_TYPE_STREAM, (File) this.body);
            } else if (this.body instanceof byte[]) {
                requestBody = RequestBody.create(CONTEXT_TYPE_STREAM, (byte[]) this.body);
            } else if (this.body instanceof Map) {
                ContextType ctype = getContextType();
                switch (ctype) {
                    case MULTIPART_FORM_DATA:
                        requestBody = createMultipartFormDataBody((Map<String, ?>) this.body);
                        break;
                    case JSON:
                        content = JsonUtils.toJson(this.body);
                        mediaType = CONTEXT_TYPE_JSON;
                        break;
                    case TEXT:
                        content = JsonUtils.toJson(this.body);
                        mediaType = CONTEXT_TYPE_TEXT;
                        break;
                    case FORM:
                    default:
                        requestBody = createFormBody((Map<String, ?>) this.body);
                        break;
                }
            } else {
                content = JsonUtils.toJson(this.body);
                mediaType = CONTEXT_TYPE_JSON;
            }

            if (requestBody == null) {
                if (StringUtils.isEmpty(content)) {
                    BodyEncrypt bodyEncrypt = this.getBodyEncrypt();
                    if (bodyEncrypt != null) {
                        try {
                            content = bodyEncrypt.encryption(content);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                requestBody = RequestBody.create(mediaType, content);
            }
            builder.method(method.getString(), requestBody);
            return requestHttp(builder.build());
        }

        private final HttpResult<R> requestHttp(okhttp3.Request request) {
            Response response;
            HttpResult.Builder result = new HttpResult.Builder();
            try {
                response = okHttpClient.newCall(request).execute();
                result.setResponse(response);
                if (response == null || !response.isSuccessful()) {
                    if (response!=null) {
                        if (response.code()==405){
                            result.setError(String.format("%s方式不支持",this.method.getString()));
                            String body = response.body().string();
                            result.setRawBodyStr(body);
                            result.setBodyStr(body);
                        }else if (response.code()==404){
                            result.setError("请求的地址不存在");
                            String body = response.body().string();
                            result.setRawBodyStr(body);
                            result.setBodyStr(body);
                        }else{
                            result.setError(String.format("服务器返回http status code %s 错误",response.code()));
                        }
                    }else{
                        result.setError("服务器返回http status code 错误");
                    }
                    return result.build();
                }

                if (downLoad || returnResponse) {
                    result.setError(null);
                    result.setResult(response);
                    return result.build();
                }
                String body = response.body().string();
                result.setRawBodyStr(body);
                result.setBodyStr(body);


                BodyEncrypt bodyEncrypt = getBodyEncrypt();
                if (bodyEncrypt != null) {
                    try {
                        String dbody = bodyEncrypt.decryption(body);
                        result.setBodyStr(dbody);
                    } catch (Exception e) {
                        e.printStackTrace();
                        result.setError("http解密失败");
                        return result.build();
                    }
                }

                body = result.getBodyStr();
                final Type type = getReturnType();
                if (type == null || type == String.class) {
                    result.setResult((R) body);
                } else {
                    if (!StringUtils.isEmpty(body)) {
                        if (type instanceof Class) {
                            result.setResult(JsonUtils.parseJson(body, (Class<? extends Object>) type));
                        } else {
                            result.setResult(JsonUtils.parseJson(body, new TypeReference() {
                                public Type getType() {
                                    return type;
                                }
                            }));
                        }
                    }
                }
                result.setError(null);
            } catch (SocketTimeoutException e) {
                e.printStackTrace();
                result.setError("连接异常");
            } catch (IOException e) {
                e.printStackTrace();
                result.setError("连接异常");
            }
            return result.build();
        }


        private final String wrapperUrl(String url) {
            url = addUrlParams(url, urlArgs);

            IUrlSignature usg = getUrlSignature();
            if (usg != null) {
                url = addUrlParams(url, usg.urlSignatureArgs());
            }
            return url;
        }

        private final void addHeader(okhttp3.Request.Builder builder, Map<String, String> headers) {
            if (builder == null || headers == null || headers.isEmpty()) {
                return;
            }
            for (String key : headers.keySet()) {
                if (StringUtils.isEmpty(key)) {
                    continue;
                }
                String value = headers.get(key);
                if (value == null) {
                    value = "";
                }
                builder.addHeader(key, value);
            }
        }

        private final void addMultipartFormData(MultipartBody.Builder builder, String name, Object v) {
            if (v == null) {
                return;
            }
            if (v instanceof File) {
                File vf = (File) v;
                builder.addFormDataPart(name, vf.getName(),
                        RequestBody.create(CONTEXT_TYPE_STREAM, vf));
            } else {
                builder.addFormDataPart(name, v.toString());
            }
        }

        private final RequestBody createMultipartFormDataBody(Map<String, ?> args) {
            if (args == null || args.isEmpty()) {
                return RequestBody.create(null, new byte[0]);
            }
            try {
                MultipartBody.Builder formBody = new MultipartBody.Builder();
                formBody.setType(MultipartBody.FORM);
                for (String key : args.keySet()) {
                    if (StringUtils.isEmpty(key)) {
                        continue;
                    }
                    Object value = args.get(key);
                    if (value == null) {
                        continue;
                    }
                    if (value instanceof List) {
                        List<Object> tmpList = (List) value;
                        if (tmpList.isEmpty()) {
                            continue;
                        }
                        for (Object o : tmpList) {
                            if (o == null) {
                                continue;
                            }
                            addMultipartFormData(formBody, key, o);
                        }
                    } else if (value.getClass().isArray()) {
                        Object[] tempArray = (Object[]) value;
                        if (tempArray.length == 0) {
                            continue;
                        }
                        for (Object o : tempArray) {
                            if (o == null) {
                                continue;
                            }
                            addMultipartFormData(formBody, key, o);
                        }
                    } else {
                        addMultipartFormData(formBody, key, value);
                    }
                }
                return formBody.build();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return RequestBody.create(null, new byte[0]);
        }

        private final RequestBody createFormBody(Map<String, ?> args) {
            if (args == null || args.isEmpty()) {
                return RequestBody.create(null, new byte[0]);
            }
            try {
                FormBody.Builder formBody = new FormBody.Builder();
                for (String key : args.keySet()) {
                    if (StringUtils.isEmpty(key)) {
                        continue;
                    }
                    Object value = args.get(key);
                    if (value == null) {
                        continue;
                    }
                    if (value instanceof List) {
                        List<Object> tmpList = (List) value;
                        if (tmpList.isEmpty()) {
                            continue;
                        }
                        for (Object o : tmpList) {
                            if (o == null) {
                                continue;
                            }
                            formBody.add(key, o.toString());
                        }
                    } else if (value.getClass().isArray()) {
                        Object[] tempArray = (Object[]) value;
                        if (tempArray.length == 0) {
                            continue;
                        }
                        for (Object o : tempArray) {
                            if (o == null) {
                                continue;
                            }
                            formBody.add(key, o.toString());
                        }
                    } else {
                        formBody.add(key, value.toString());
                    }
                }
                return formBody.build();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return RequestBody.create(null, new byte[0]);
        }


    }




    private static String addUrlParams(String url, Map<String, ?> args) {
        if (StringUtils.isEmpty(url) || args == null || args.isEmpty()) {
            return url;
        }
        String arg = formUrlEncode(args);
        if (StringUtils.isEmpty(arg)) {
            return url;
        }
        if (url.indexOf("?") == -1) {
            url = String.format("%s?%s", url, arg);
        } else {
            url = String.format("%s&%s", url, arg);
        }
        return url;
    }


    private static String formUrlEncode(Map<String, ?> args) {
        if (args == null || args.isEmpty()) {
            return "";
        }
        try {
            StringBuilder arg = new StringBuilder();
            for (String key : args.keySet()) {
                if (StringUtils.isEmpty(key)) {
                    continue;
                }
                Object value = args.get(key);
                if (value == null) {
                    continue;
                }
                if (value instanceof List) {
                    List<Object> tmpList = (List) value;
                    if (tmpList.isEmpty()) {
                        continue;
                    }
                    for (Object o : tmpList) {
                        if (o == null) {
                            continue;
                        }
                        arg.append(String.format("%s=%s&", key, o.toString()));
                    }
                } else if (value.getClass().isArray()) {
                    Object[] tempArray = (Object[]) value;
                    if (tempArray.length == 0) {
                        continue;
                    }
                    for (Object o : tempArray) {
                        if (o == null) {
                            continue;
                        }
                        arg.append(String.format("%s=%s&", key, o.toString()));
                    }
                } else {
                    arg.append(String.format("%s=%s&", key, value.toString()));
                }
            }
            if (arg.length() > 0) {
                arg.setLength(arg.length() - 1);
            }
            return arg.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

}